package org.plumecache.springboot.autoconfigurer.controller;

import com.google.gson.Gson;
import com.plumecache.core.CacheService;
import com.plumecache.core.CacheServiceFactory;
import com.plumecache.core.StatisticsService;
import com.plumecache.core.common.StatisticsDTO;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.plumecache.springboot.autoconfigurer.controller.vo.CacheCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

@RestController
@CrossOrigin
@RequestMapping("/plumecache")
@ConditionalOnWebApplication
public class PlumecacheController {

    private final Gson gson = new Gson();
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private StatisticsService statisticsService;

    @GetMapping("list")
    public ResponseEntity<List<StatisticsDTO>> list() {
        return ResponseEntity.ok(statisticsService.getStatisticsDTOList());
    }

    private final Map<String, Function<CacheCommand, String>> commands = new HashMap<>();

    @PostConstruct
    private void initialize() {
        commands.put("get", command -> command.getCacheInstance().get(command.getKey()));

        commands.put("set", command -> {
            command.getCacheInstance().set(command.getKey(), command.getValue());
            return "ok";
        });

        commands.put("del", command -> {
            command.getCacheInstance().delete(command.getKey());
            return "ok";
        });

        commands.put("hget", command -> {
            command.getCacheInstance().hget(command.getKey(), command.getField(), String.class);
            return "ok";
        });

        commands.put("hset", command -> {
            command.getCacheInstance().hset(command.getKey(), command.getField(), command.getValue());
            return "ok";
        });

        commands.put("hdel", command -> {
            command.getCacheInstance().hdel(command.getKey(), command.getField());
            return "ok";
        });
    }

    @PostMapping("execute")
    public String execute(@RequestBody CacheCommand cacheCommand) {
        if (log.isDebugEnabled()) {
            log.debug("execute command,{}", gson.toJson(cacheCommand));
        }

        String instanceName = cacheCommand.getInstanceName();
        CacheService cacheService = CacheServiceFactory.getInstance(instanceName);
        if (cacheService == null) {
            return String.format("cache instance %s no find", instanceName);
        }

        cacheCommand.setCacheInstance(cacheService);

        try {
            Optional<Function<CacheCommand, String>> function = Optional.ofNullable(commands.get(cacheCommand.getCommand()));
            if (function.isPresent()) {
                return function.get().apply(cacheCommand);
            }

            if (log.isWarnEnabled()) {
                log.warn("command not support,command:{}", gson.toJson(cacheCommand));
            }
            return String.format("command not support,%s", gson.toJson(cacheCommand));
        } catch (Exception e) {
            log.error("command execute error,command:{},ex:{}", gson.toJson(cacheCommand), ExceptionUtils.getStackTrace(e));
            return String.format("command execute error:%s", ExceptionUtils.getStackTrace(e));
        }
    }

}
